/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.core.action.retrieve;

import com.inspur.edp.bef.api.be.IBEContext;
import com.inspur.edp.bef.api.parameter.retrieve.RetrieveParam;
import com.inspur.edp.bef.core.be.CoreBEContext;
import com.inspur.edp.bef.core.lock.LockService;
import com.inspur.edp.bef.core.lock.LockUtils;
import com.inspur.edp.bef.core.scope.ScopeNodeParameter;
import com.inspur.edp.bef.core.scope.SingleBETypeExtension;
import com.inspur.edp.cef.api.repository.IRootRepository;
import com.inspur.edp.cef.api.scope.ICefScopeNodeParameter;
import com.inspur.edp.cef.entity.condition.RetrieveFilter;
import com.inspur.edp.cef.entity.entity.IEntityData;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

public class CheckVersionExtension extends SingleBETypeExtension<CheckVersionScopeNodeParameter> {

    public CheckVersionExtension() {
        super();
    }

    @Override
    public void onExtendSetComplete() {
        IBEContext context = null;
        if (getParameters() != null && getParameters().size() > 0)
            context = ((ScopeNodeParameter) getParameters().get(0)).getBEContext();
        //〇 批量加锁:
        if (LockUtils.needLock(context.getModelResInfo()))
            LockService.getInstance().addLocks(getCurrentBeType(), getNeedLockIds());
        //① 批量校验；
        List<String> checkVersionResult = multiCheckVersion();
        //② 构造版本校验不通过的idList，到DAL取；
        HashMap<String, IEntityData> dicData = multiRetrieveFromDAL(checkVersionResult);
        //③ 执行回调函数；
        executeAction(dicData);
    }

    private List<String> getNeedLockIds() {
        List<String> needLockParas = new ArrayList<>();
        for (CheckVersionScopeNodeParameter item : getBEParameters()) {
            if (item.getParam().getNeedLock()) {
                needLockParas.add(item.getBEContext().getID());
            }
        }
        return needLockParas;
    }

    /**
     * 版本校验不通过的执行回调函数
     *
     * @param dicData Retrieve结果
     */
    private void executeAction(HashMap<String, IEntityData> dicData) {
        if (dicData == null || dicData.size() == 0) {
            return;
        }
        for (ICefScopeNodeParameter parameter : getParameters()) {
            CoreBEContext context = (CoreBEContext) ((CheckVersionScopeNodeParameter) parameter).getBEContext();
            if (dicData.containsKey(context.getID())) {
                context.clearData();
            }
            if (dicData.get(context.getID()) != null) {
                ((CheckVersionScopeNodeParameter) parameter).executeAction(context, dicData.get(context.getID()));
            }
        }

    }

    private List<String> multiCheckVersion() {
        List<String> idList = getBEParameters().stream().map(a -> a.getBEContext().getID()).collect(Collectors.toList());
        HashMap<String, Date> versionDic = getVersionControlValues(idList);
        List<String> list = new ArrayList<>(versionDic.size());
        for (ScopeNodeParameter par : getBEParameters()) {
            String id = par.getBEContext().getID();
            Date currentVersion = new Date(0);
            if (versionDic.containsKey(id) && versionDic.get(id) != null) {
                currentVersion = versionDic.get(id);
            } else {
                list.add(id);
                continue;
            }
            boolean result = (currentVersion.compareTo(new Date(0)) != 0)
                    && (par.getBEContext().getBizEntity().getVersionControlPropValue() != null
                    && currentVersion.compareTo(par.getBEContext().getBizEntity().getVersionControlPropValue()) == 0);
            if (!result) {
                list.add(id);
            }
        }
        return list;
    }

    private HashMap<String, Date> getVersionControlValues(List<String> idList) {
        IRootRepository repository = getSessionItem().getBEManager().getRepository();
        if(idList.size() == 1) {
            HashMap<String,Date> rez = new HashMap<>(2);
            rez.put(idList.get(0), repository.getVersionControlValue(idList.get(0)));
            return rez;
        } else {
            return repository.getVersionControlValues(idList);
        }
    }

    private HashMap<String, IEntityData> multiRetrieveFromDAL(List<String> checkVersionResult) {
        if (checkVersionResult.size() == 0) {
            return null;
        }
        IRootRepository repository = getSessionItem().getBEManager().getRepository();
        RetrieveFilter rf = getRetrieveFilter();
        try {
            List<IEntityData> retrieve;
            HashMap<String, IEntityData> dateHashMap = new HashMap<>();
            for (String s : checkVersionResult) {
                dateHashMap.put(s, null);
            }
            if (rf != null) {
                retrieve = repository.retrieve(checkVersionResult, rf);
            } else {
                retrieve = repository.retrieve(checkVersionResult);
            }
            if (retrieve != null && retrieve.size() > 0) {
                for (IEntityData data : retrieve) {
                    dateHashMap.put(data.getID(), data);
                }
            }
            return dateHashMap;
//			return null;
//			return rf != null ? repository.retrieve(checkVersionResult, rf)
//					: repository.retrieve(checkVersionResult);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    private RetrieveFilter getRetrieveFilter() {
        RetrieveParam rp = getBEParameters().get(0).getParam();
        return rp != null ? rp.getRetrieveFilter() : null;
    }
}
